/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "ui节点库滚动视口.h"
#include "框架/工作区/ui节点面板.h"

#include <文件/file_文件名数据.h>



static C_StrKey分配器 g名称分配器;
static S_库节点加载   g库模块加载信息;

static std::set<C_节点基类*> m_Nodes;



static void on_节点库滚动视口绘制(C_Widget* self, S_2D画布* 画布) {
	C_节点库滚动视口* view = static_cast<C_节点库滚动视口*>(self);

	view->m_背景绘制.m_属性 = f_vg_gen属性(画布);
	S_凸边图元 图元{};
	图元.属性 = f_vg_get属性(画布, view->m_背景绘制.m_属性);

	view->m_背景绘制.f_Draw(画布, 图元, E_笔刷类型::e_单色填充);

	view->m_图标绘制.f_Draw彩色(画布, view->m_背景绘制.m_属性, S_节点UI主题::ui_节点图标);

	auto 字体 = f_surface_get字体(*self->m_UIctx, S_UI主题::ui_默认字体);
	view->m_字符绘制.f_Draw(画布, &字体, view->m_背景绘制.m_属性);

}

static void on_节点库滚动视口布局(C_Widget* self, C_Widget** ws, uint32 num) {
	if( !num ) return;

	C_节点库滚动视口* view = static_cast<C_节点库滚动视口*>(self);
	uint32 offset = 0;

	vec2 size = view->m_项大小 + 10;
	vec2 滚动坐标 = view->m_滚动坐标;

	float32 项宽度 = view->m_项大小.x + 10;
	float32 项高度 = view->m_项大小.y + 10;

	int32 列数量 = view->m_Size.x / size.x;
	if (!列数量) return;
	int32 行数量 = view->m_项数据.size() / 列数量;
	
	f_widget_layout_V滚动钳制(view->m_滚动坐标.y, view->m_Size.y, { 行数量, 列数量 }, 项高度, view->m_项数据.size());


	uint32 y = 0;
	for (; y < 行数量; ++y) {
		for (uint32 x = 0; x < 列数量; ++x) {
			ws[offset]->f_setPos({ x * size.x + 40, y * size.y + 滚动坐标.y });
			++offset;
		}
	}

	行数量 *= 列数量;
	列数量 = view->m_项数据.size() - 行数量;
	for (uint32 x = 0; x < 列数量; ++x) {
		ws[offset]->f_setPos({ x * size.x + 40, y * size.y + 滚动坐标.y });
		++offset;
	}
}

static void on_节点库滚动视口调整(C_Widget* self) {
	C_节点库滚动视口* view = static_cast<C_节点库滚动视口*>(self);

	auto e = self->f_get更新部件();

	view->m_背景绘制.f_alloc(e.m_Num * 2);
	view->m_图标绘制.f_alloc(e.m_Num);
	view->m_字符绘制.f_alloc(e.m_Num*2, 24);

	for (uint32 i = 0; i < e.m_Num; ++i) {
		C_项面板项* item = static_cast<C_项面板项*>(e.m_W[i]);
		uint32 offset = i*2;

		vec2 pos = e.m_W[i]->m_Pos;

		mat3X2 mat;
		mat.row0 = e.m_W[i]->m_Pos;
		mat.row1 = e.m_W[i]->m_Size;
		mat.row2 = { S_UI主题::ui_面板圆角半径, 0 };

		view->m_背景绘制.f_set单色填充(offset, mat, { 100,100,100,100 }, S_Widget预设图元::m_圆角矩形);

		float32 icoSize = e.m_W[i]->m_Size.y * 0.5f;
		mat.row0.x += 2;
		mat.row0.y += 2;
		mat.row1 = { icoSize, icoSize };
		view->m_背景绘制.f_set单色填充(offset + 1, mat, { 100,100,100,255 }, S_Widget预设图元::m_圆角矩形);

		mat.row0.x += 2 + icoSize * 0.5;
		mat.row0.y += 2 + icoSize * 0.5;
		mat.row1 = { icoSize, icoSize };
		//auto item = view->m_项数据[i];
		view->m_图标绘制.f_set(item->m_项.m_ico, i, mat, {});
		

		mat.row0 = { pos.x + 2, pos.y + e.m_W[i]->m_Size.y - 26 };
		mat.row1.x = e.m_W[i]->m_Size.x;
		mat.row1.y = icoSize;
		view->m_字符绘制.f_绘制文本({ mat.row0, mat.row1 }, S_UI主题::uic_文字颜色, offset, item->m_项.m_item.front(), E_对齐方式::e_据中对齐);
		mat.row0 = { pos.x + icoSize + 4, pos.y};
		mat.row1 = { e.m_W[i]->m_Size.x - icoSize, e.m_W[i]->m_Size.y * 0.4f };
		view->m_字符绘制.f_绘制文本({ mat.row0, mat.row1 }, S_UI主题::uic_文字颜色, offset+1, item->m_项.m_item.back(), E_对齐方式::e_左对齐);
	}

}

static bool on_滚动视口(C_Widget* self, const S_鼠标& 鼠标) {
	C_节点库滚动视口* view = static_cast<C_节点库滚动视口*>(self);

	auto e = self->f_get更新部件();

	view->m_滚动坐标.y += 鼠标.lZ * 30;
	
	float32 项宽度 = view->m_项大小.x + 10;
	float32 项高度 = view->m_项大小.y + 10;

	int32 列数量 = view->m_Size.x / 项宽度;
	int32 行数量 = view->m_项数据.size() / 列数量;

	f_widget_layout_V滚动钳制(view->m_滚动坐标.y, view->m_Size.y, { 行数量, 列数量 }, 项高度, view->m_项数据.size());
	
	view->m_绘制属性更新 = true;
	return true;
}

static void f_库文件_保存(FILE* f) {
	f_node后端_保存库节点(m_Nodes, f);
	m_Nodes.clear();
}

static bool on_库视口_拖拽放下(C_Widget* self, C_Widget* 发起组件, S_拖放数据& data) {
	if (data.m_Type == E_自定义拖放数据类型::e_拖放_节点子集按钮) {
		C_节点库滚动视口* view = static_cast<C_节点库滚动视口*>(self);

		std::cout << "保存节点到库 : " << self << std::endl;
		S_插座拖放数据* 拖放数据 = (S_插座拖放数据*)(data.m_Next);
		//拖放数据->发起的节点;
		//拖放数据->发起的节点树;
		m_Nodes = { 拖放数据->发起的节点->m_NodeData };

		std::string name = 拖放数据->发起的节点->m_NodeData->f_getName();
		std::string path = S_框架::m_库默认路径 + name + ".node";
		std::wstring itemName = g名称分配器.f_Gen(f_StringToWString(name));
		
		name = f_WStringToString(itemName);
		path = S_框架::m_库默认路径 + name + ".node";

		f_node后端_所有节点树设置为准备保存状态();
		f_file_备份保存文件(path, f_库文件_保存);

		f_库视口_添加节点项(view, itemName, 拖放数据->发起的节点->m_ICO);
		
	}
	return false;
}

static E_事件是否传递 on_库项_开始拖拽(C_Widget* self, const S_鼠标& 鼠标, S_拖放数据& data) {
	C_项面板项* item = static_cast<C_项面板项*>(self);
	g库模块加载信息.m_Path = S_框架::m_库默认路径 + f_WStringToString(item->m_项.m_item.front()) + ".node";

	data.m_Type = E_自定义拖放数据类型::e_拖放_库项加载;
	data.m_Next = &g库模块加载信息;


	return E_事件是否传递::e_事件传递_继续;
}

static E_事件是否传递 on_库项_拖拽(C_Widget* self, const S_鼠标& 鼠标, S_拖放数据& data) {
	//std::cout << "on_库项_拖拽 : " << 鼠标.lPos.x << std::endl;

	return E_事件是否传递::e_事件传递_继续;
}

static bool on_库项_结束拖动(C_Widget* self, C_Widget* 拾取的部件, S_拖放数据& data) {
	switch (data.m_Type) {
		case E_自定义拖放数据类型::e_拖放_节点子集按钮: {
			std::cout<<"替换库节点"<<std::endl;
			C_项面板项* item = dynamic_cast<C_项面板项*>(self);

			if (item) {
				S_插座拖放数据* 拖入的节点 = (S_插座拖放数据*)data.m_Next;
				拖入的节点->发起的节点;

				auto 老文件 = S_框架::m_库默认路径 + f_WStringToString(item->m_项.m_item[0]) + ".node";
				//auto 新文件名 = f_WStringToString(g名称分配器.f_Gen(拖入的节点->发起的节点->m_NodeData->f_getWName()));
				f_node后端_所有节点树设置为准备保存状态();
				f_node后端_覆盖保存库节点(老文件, { 拖入的节点->发起的节点->m_NodeData });
			}
			
			break;
		}
		default:
			break;
	}
	return true;
}

static bool on_库项鼠标进入(C_Widget* self, const S_鼠标& 轮值) {
	C_节点库滚动视口* box = static_cast<C_节点库滚动视口*>(self->m_父部件);
	C_项面板项* item = static_cast<C_项面板项*>(self);
	mat3X2 Mat;
	Mat.row0 = self->m_Pos;
	Mat.row1 = self->m_Size;
	Mat.row2 = { S_UI主题::ui_面板圆角半径, 0 };

	box->m_背景绘制.f_alloc(box->m_项数据.size() * 2);
	box->m_背景绘制.f_set单色填充(item->m_项.m_ID_X * 2, Mat, S_UI主题::uic_菜单焦点色, S_Widget预设图元::m_圆角矩形);
	
	return false;
}

static bool on_库项鼠标移出(C_Widget* self, const S_鼠标& 轮值) {
	C_节点库滚动视口* box = static_cast<C_节点库滚动视口*>(self->m_父部件);
	C_项面板项* item = static_cast<C_项面板项*>(self);

	mat3X2 Mat;
	Mat.row0 = self->m_Pos;
	Mat.row1 = self->m_Size;
	Mat.row2 = { S_UI主题::ui_面板圆角半径, 0 };

	box->m_背景绘制.f_alloc(box->m_项数据.size() * 2 + 1);
	box->m_背景绘制.f_set单色填充(item->m_项.m_ID_X * 2, Mat, { 100,100,100,100 }, S_Widget预设图元::m_圆角矩形);
	
	return true;
}


C_节点库滚动视口::C_节点库滚动视口(S_UI创建环境& ctx) : C_Widget(&ctx) {
	mf_DrawFun = on_节点库滚动视口绘制;
	mf_布局Fun = on_节点库滚动视口布局;
	mf_变换修改 = on_节点库滚动视口调整;
	mf_鼠标滚轮 = on_滚动视口;
	mf_结束拖拽 = on_库视口_拖拽放下;

	m_项大小 = { 120, 60 };
	m_滚动坐标 = {};
}

C_节点库滚动视口::~C_节点库滚动视口() {
}







void f_库视口_添加节点项(C_节点库滚动视口* view, std::wstring name, std::string ico, int32 ID) {
	
	auto* butItem = new C_项面板项;
	butItem->f_setSize(view->m_项大小);

	if (ID < 0) {
		ID = view->m_项数据.size();
	}

	butItem->m_项.m_item = { name, L"说明:"};
	butItem->m_项.m_Data = nullptr;
	butItem->m_项.m_ico = ico;
	butItem->m_项.m_ico_color = {200,200,200,255};
	butItem->m_项.m_ID_X = ID;
	butItem->mf_开始拖拽 = on_库项_开始拖拽;
	butItem->mf_拖拽 = on_库项_拖拽;
	butItem->mf_结束拖拽 = on_库项_结束拖动;

	butItem->mf_鼠标进入 = on_库项鼠标进入;
	butItem->mf_鼠标离开 = on_库项鼠标移出;
	//view->f_添加子组件(butItem);
	f_widget_push待添加部件(view, butItem, -1, true);


	S_鼠标双击键位映射* 鼠标双击键位 = f_widget_alloc_鼠标双击键位映射();
	鼠标双击键位->event = f_NodeView_载入节点;
	鼠标双击键位->鼠标按键[0] = E_Input_鼠标按键::e_左键;
	鼠标双击键位->鼠标状态[0] = DEF_按键状态_按下;
	鼠标双击键位->发生组件 = butItem;
	f_ui_注册鼠标快捷键(butItem, (S_键位映射*)鼠标双击键位);

	view->m_项数据.push_back({ "", {}, {name}, {}, (void*)butItem, (int32)ID });
}

void f_库视口_加载模块(C_节点库滚动视口* view, std::string 目录路径) {
	S_目录文件包 文件包;
	std::vector<std::string> 扩展名过滤 = {".ex", ".bc", ".node"};
	f_file_get目录下所有文件名(目录路径, 文件包, 扩展名过滤);

	f_widget_remove子部件(view, 0, -1, true);
	view->m_项数据.clear();

	std::vector<C_Widget*> items;
	uint32 num = 文件包.文件.size();

	g名称分配器.f_Clear();
	for (uint32 i = 0; i < num; ++i) {
		auto& file = 文件包.文件[i];
		auto name = f_file_取无后缀文件名(file);
		
		g名称分配器.f_Gen(name);

		auto path = 目录路径 + f_WStringToString(file);
		auto f = fopen(path.c_str(), "rb");

		std::string ico_info[2];
		if (f) {
			f_node后端_加载库节点信息(ico_info, f);
			//ico = f_读取字符串(f);
			fclose(f);
		}
		f_库视口_添加节点项(view, name, ico_info[0], i);
	}
	
	view->m_绘制属性更新 = true;
}

E_事件是否传递 f_NodeView_载入节点(C_Widget* self, uint8 状态) {
	C_项面板项* item = static_cast<C_项面板项*>(self);

	item->m_项.m_Data;
	std::cout << "f_NodeView_载入节点 : " << item->m_项.m_Data << std::endl;
	return E_事件是否传递::e_事件传递_终止;
}


